/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package db21;
import com.hp.hpl.jena.ontology.Individual;
import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.racersystems.jracer.*;
import db21.entities.DigitalEducationalResourceTypes;
import db21.entities.Entities;
import db21.listeners.ClosingOnlyListener;
import db21.racerpro.RacerProResult;
import java.awt.BorderLayout;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.UIManager;

/**
 * Main class of project
 * @author Mamontov Dmitry
 */
public class Application {

 
    KBConnection  m_conn;
    EnumMap<ApplicationMode, JFrame> m_forms;
    Process       m_racerProProcess;
    
    public Application(KBConnection conn) {
        m_conn = conn;
        m_racerProProcess = null;
        
        try { 
            UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); 
        } catch (Exception ex) { 
            ex.printStackTrace(); 
        }
        
        m_forms = new EnumMap<ApplicationMode, JFrame>(ApplicationMode.class);
        createForm(ApplicationMode.MainForm, MainFormView.class);
        createForm(ApplicationMode.EducationalResources, ResourcesView.class);
        createForm(ApplicationMode.Collections, CollectionsView.class);
        createForm(ApplicationMode.SeekResources, SearchResourcesView.class);
        createForm(ApplicationMode.Competences, CompetenceView.class);
        createForm(ApplicationMode.Subjects, SubjectsView.class);
        createForm(ApplicationMode.Themes, ThemeView.class);
        createForm(ApplicationMode.Console, ConsoleView.class);
        
        JFrame mainWindow =  m_forms.get(ApplicationMode.MainForm);
        mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        mainWindow.addWindowListener( new ClosingOnlyListener() {

            @Override
            public  void windowClosing(WindowEvent e) {
                Application.this.finish();
            }
            
        });
        
    }
    
    public final void setMode(ApplicationMode mode) {
       Iterator it = m_forms.entrySet().iterator();
       while(it.hasNext()) {
           Map.Entry<Application, JFrame> e = 
          (Map.Entry<Application, JFrame>)it.next();
           
           e.getValue().setVisible(false);
       }
       JFrame f = m_forms.get(mode);
       ApplicationPanel p = (ApplicationPanel)(f.getContentPane());
       f.setVisible(true);
       p.fireModelUpdate();
    } 
    
    
    public final <T extends ApplicationPanel> 
            void createForm(ApplicationMode m, Class<T> _class) {
        JFrame f = this.createFrame(_class);
        f.setTitle(m.title());
        m_forms.put(m, f);
    }
    
    public <T extends Entities> T resource(Class<T> _class)  {
        T result = null;
        try {
            result = _class.newInstance();
            result.set(m_conn);
        } catch (Exception ex) {
        } 
        return result;
    }
    
    public final  <T extends ApplicationPanel> JFrame createFrame(Class<T> _class) {
        JFrame result = new JFrame();
        result.setLayout(new BorderLayout());
        T view = null;
        try {
            view = _class.newInstance();
            view.setModel(this);
            
            result.setMaximumSize(view.getPreferredSize());
            result.setMinimumSize(view.getPreferredSize());
            result.setSize(view.getPreferredSize());
            result.setResizable(false);
            result.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
            result.setContentPane(view);
        } catch (InstantiationException ex) {
            Logger.getLogger(Application.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(Application.class.getName()).log(Level.SEVERE, null, ex);
        }
        return result;
    }
    
    public void attachRacerProProcess(Process proc) {
        m_racerProProcess = proc;
    }
    
    public void finish() {
        m_conn.close();
        if (m_racerProProcess != null) {
            m_racerProProcess.destroy();
        }
    }
    
    public void tryStartApplication() {
        if (m_conn.open() == false) {
            JOptionPane.showMessageDialog(null, "Can't establish a connection");
            finish();
        } else {
            setMode(ApplicationMode.MainForm);
        }
    }
    
    public void save()  {
        m_conn.save();
    }
    
    public KBConnection getConnection() {
        return m_conn;
    }
    
    public static Process tryStartRacerPro(String[] args) {
        boolean canStartRacerPro = (args.length != 0); 
        Process racerProProcess = null;
        if (canStartRacerPro) {
            ProcessBuilder racerProProcessBuilder = new ProcessBuilder(args[0],  
                "--",  "-u", "-ef", "@UTF8");
            try {
                racerProProcess = racerProProcessBuilder.start();
                // Wait for RacerPro to start
                Thread.sleep(1000);
            } catch (IOException ex) {
                System.out.println("Can't start RacerPro with error " + ex.getMessage());
            } catch (InterruptedException ex) {
                System.out.println("Caught interrupted exception. Being Java is suffering");
            }
        }
        return racerProProcess;
    }
    
    
     
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args)  {
        // Start server of RacerPro if can
        Process racerProProcess = tryStartRacerPro(args);
        // Start application
        String source = "eduresources.owl";
        String prefix = "http://127.0.0.1/er#";
        boolean isAbsolute = false;
        String ip = "127.0.0.1";
        int port = 8088;
        
        KBConnection conn = new KBConnection(ip, port, isAbsolute, source, prefix);
        
        
        Application app = new Application(conn);
        app.attachRacerProProcess(racerProProcess);
        app.tryStartApplication();
    }
}
